Skip to content

Optimize search request handling with debouncing and AbortController#492

Merged
mehul-m-prajapati merged 2 commits into
GitMetricsLab:mainfrom
ABHImaybeJEET:main
May 29, 2026
Merged

Optimize search request handling with debouncing and AbortController#492
mehul-m-prajapati merged 2 commits into
GitMetricsLab:mainfrom
ABHImaybeJEET:main

Conversation

@ABHImaybeJEET
Copy link
Copy Markdown
Contributor

@ABHImaybeJEET ABHImaybeJEET commented May 24, 2026

Related Issue


Description

Optimized the GitHub tracker search request handling to prevent unnecessary API consumption, minimize hitting GitHub rate limits, and eliminate flickering or out-of-order UI updates:

  • Debouncing search input: Introduced a 500ms debounce timer for the GitHub Username input in Tracker.tsx so that requests are only fired after the user pauses typing. Clicking "Fetch Data" or submitting the form sets the debounced value immediately to trigger the request without double-fetching.
  • Request cancellation (AbortController): Configured an AbortController inside useGitHubData.ts that aborts any active in-flight requests immediately when a new fetch is initiated.
  • Octokit integration: Passed the AbortSignal to the Octokit request options (request: { signal }), allowing clean request aborts at the HTTP request layer.
  • Latest response validation: Ensured only the latest search response is allowed to update the state and render in the UI.

How Has This Been Tested?

  • Ran npm run build locally to verify that all 3,015 modules build and compile into production assets successfully with no TypeScript compiler errors.
  • Verified that when a new search is triggered during an active fetch, the previous request is cancelled gracefully and the UI updates cleanly with only the final results.

Type of Change

  • Bug fix
  • New feature
  • Code style update
  • Breaking change
  • Documentation update

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Improved request lifecycle management to prevent stale data updates from superseded GitHub searches.
    • In-flight requests are now properly cancelled and cleaned up when components unmount.
  • Performance

    • Search requests are now debounced to reduce unnecessary API calls during rapid user input.

Review Change Stack

@netlify
Copy link
Copy Markdown

netlify Bot commented May 24, 2026

Deploy Preview for github-spy ready!

Name Link
🔨 Latest commit cf30cdb
🔍 Latest deploy log https://app.netlify.com/projects/github-spy/deploys/6a19c2a2609e03000869ca4f
😎 Deploy Preview https://deploy-preview-492--github-spy.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 24, 2026

Warning

Review limit reached

@mehul-m-prajapati, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 46 minutes and 44 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1585af69-7fec-49b3-86c5-1360a3f316bb

📥 Commits

Reviewing files that changed from the base of the PR and between 09cf09d and cf30cdb.

📒 Files selected for processing (1)
  • src/pages/Tracker/Tracker.tsx
📝 Walkthrough

Walkthrough

This PR implements optimized search request handling to address excessive GitHub API calls during rapid typing. It adds AbortController support to the useGitHubData hook to cancel in-flight requests and introduces debounced username input in the Tracker component to delay fetch requests until the user pauses typing.

Changes

Debounced Search with Request Cancellation

Layer / File(s) Summary
Request Cancellation in useGitHubData
src/hooks/useGitHubData.ts
Hook now creates and manages an AbortController ref per fetch cycle. When fetchData is called, it aborts any previous controller and creates a new one. The pagination helper accepts an optional AbortSignal and forwards it to Octokit GET /search/issues requests. Per-request rejection handlers detect AbortError and return early; post-Promise.allSettled consolidation also checks for abort errors and returns early; the catch block ignores AbortError. Loading state reset moves to a finally block gated by stale-check (matching requestId and active controller), and an unmount useEffect aborts any active controller.
Debounced Username Fetching in Tracker
src/pages/Tracker/Tracker.tsx
Adds debouncedUsername state that synchronizes 500ms after username changes (clears when username is falsy). Data fetching moves into a useEffect that depends on debouncedUsername, tab, and page, calling fetchData(debouncedUsername, page + 1, ROWS_PER_PAGE) when non-empty. The submit handler now only resets page and sets debouncedUsername, removing the immediate fetchData call.

Sequence Diagram(s)

sequenceDiagram
  participant Component
  participant fetchData
  participant AbortController
  participant Octokit
  
  Component->>fetchData: call fetchData(username)
  fetchData->>AbortController: abort previous controller
  fetchData->>AbortController: create new controller
  fetchData->>Octokit: GET /search/issues with signal
  Note over Octokit: request in-flight
  Component->>fetchData: call fetchData(new username)
  fetchData->>AbortController: abort active controller
  Octokit-->>fetchData: AbortError rejected
  fetchData->>fetchData: detect AbortError, return early
  fetchData->>Component: skip state updates
  fetchData->>Component: finally: reset loading (if stale check passes)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • GitMetricsLab/github_tracker#355: Both PRs modify src/hooks/useGitHubData.ts to cancel in-flight Octokit search/issues requests using AbortController and update src/pages/Tracker/Tracker.tsx to debounce username-driven fetching so stale responses don't update state.
  • GitMetricsLab/github_tracker#149: Both PRs modify src/hooks/useGitHubData.ts's fetchData/pagination helper used for GitHub search requests, so the changes are directly related at the code level.
  • GitMetricsLab/github_tracker#298: Both PRs modify src/hooks/useGitHubData.ts request-result handling, with this PR updating the hook's error flow to ignore AbortError.

Suggested labels

quality:clean, level:intermediate, type:feature

Poem

A rabbit hops through GitHub's maze,
Cancelling requests in a thousand ways,
With debounce and abort, we pause the chase—
One final fetch, at the right pace! 🐰⚡

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main changes: debouncing and AbortController optimization for search request handling.
Description check ✅ Passed The description comprehensively covers all required template sections with detailed explanations of changes, testing approach, and type of change classification.
Linked Issues check ✅ Passed The PR fully addresses all coding requirements from issue #337: debounced input (500ms), AbortController for request cancellation, Octokit signal integration, latest response validation, and comprehensive testing.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the requirements of issue #337; no unrelated modifications detected in the hook or page components.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/hooks/useGitHubData.ts (1)

104-115: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Empty-search transitions do not cancel the active request.

The new abort path only runs after the !username.trim() / rateLimited guard. When Tracker.tsx clears the debounced username and suppresses the next fetch, the previous controller stays active, so that stale response can still pass the requestId/controller checks and repopulate state after the input is blank. Abort the current controller before this guard, or expose an explicit cancel/reset path for empty searches.

Suggested minimal fix
-      if (!octokit || !username.trim() || rateLimited) {
-        return;
-      }
-
-      // Cancel any active in-flight request before triggering a new one
       if (abortControllerRef.current) {
         abortControllerRef.current.abort();
       }
+
+      if (!octokit || !username.trim() || rateLimited) {
+        return;
+      }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/hooks/useGitHubData.ts` around lines 104 - 115, The guard in
useGitHubData currently returns before aborting an in-flight request, so
clearing the debounced username can leave a previous request active; move or
duplicate the abort logic so abortControllerRef.current?.abort() runs before the
early-return (i.e., before checking !username.trim() || rateLimited), or add an
explicit cancel/reset path that calls abortControllerRef.current.abort(), clears
abortControllerRef.current, and increments/invalidates requestId when username
becomes empty; update references to abortControllerRef and requestId in the hook
(where controller is created and assigned) to ensure stale responses cannot
repopulate state after an empty search.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/pages/Tracker/Tracker.tsx`:
- Around line 105-109: handleSubmit currently both sets state (setPage,
setDebouncedUsername) and calls fetchData directly, causing duplicate requests;
remove the direct fetchData(username, 1, ROWS_PER_PAGE) call and instead drive
the effect that performs fetching from changes to debouncedUsername/page by
introducing a submit counter (e.g., submitCount state and setSubmitCount(c =>
c+1)) that the effect also depends on so the button can force refresh the same
username/page without calling fetchData manually; update the effect to include
submitCount alongside debouncedUsername and page and call fetchData from there.

---

Outside diff comments:
In `@src/hooks/useGitHubData.ts`:
- Around line 104-115: The guard in useGitHubData currently returns before
aborting an in-flight request, so clearing the debounced username can leave a
previous request active; move or duplicate the abort logic so
abortControllerRef.current?.abort() runs before the early-return (i.e., before
checking !username.trim() || rateLimited), or add an explicit cancel/reset path
that calls abortControllerRef.current.abort(), clears
abortControllerRef.current, and increments/invalidates requestId when username
becomes empty; update references to abortControllerRef and requestId in the hook
(where controller is created and assigned) to ensure stale responses cannot
repopulate state after an empty search.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 03e1e069-06d3-48aa-abc0-3bc200419c02

📥 Commits

Reviewing files that changed from the base of the PR and between 6c6bc3e and 09cf09d.

📒 Files selected for processing (2)
  • src/hooks/useGitHubData.ts
  • src/pages/Tracker/Tracker.tsx

Comment on lines 105 to 109
const handleSubmit = (e: React.FormEvent<HTMLFormElement>): void => {
e.preventDefault();
setPage(0);
setDebouncedUsername(username);
fetchData(username, 1, ROWS_PER_PAGE);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Submit still triggers the same search twice.

Updating debouncedUsername already schedules the effect-based fetch. The extra fetchData(...) here sends a second identical request whenever the submitted username differs from the current debounced value or page resets, so the hook immediately aborts one of the two calls. Keep a single trigger path here; if the button must refresh the same username/page, drive the effect with a submit counter instead of calling fetchData directly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/Tracker/Tracker.tsx` around lines 105 - 109, handleSubmit currently
both sets state (setPage, setDebouncedUsername) and calls fetchData directly,
causing duplicate requests; remove the direct fetchData(username, 1,
ROWS_PER_PAGE) call and instead drive the effect that performs fetching from
changes to debouncedUsername/page by introducing a submit counter (e.g.,
submitCount state and setSubmitCount(c => c+1)) that the effect also depends on
so the button can force refresh the same username/page without calling fetchData
manually; update the effect to include submitCount alongside debouncedUsername
and page and call fetchData from there.

@ABHImaybeJEET
Copy link
Copy Markdown
Contributor Author

@mehul-m-prajapati
Hey this has been Gssoc approved and submitted since few days , It would be great if you could update the results tab from your side .

@mehul-m-prajapati mehul-m-prajapati merged commit 0620c37 into GitMetricsLab:main May 29, 2026
0 of 2 checks passed
@github-actions
Copy link
Copy Markdown

🎉🎉 Thank you for your contribution! Your PR #492 has been merged! 🎉🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve Search Request Handling to Prevent Excessive GitHub API Calls During Rapid Input

2 participants